// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//

#pragma once
#include <string>
#include <vector>
#include <iostream>
#include <cantor/parser/ast/dml.h>
#include <cantor/parser/ast/ddl.h>
#include <cantor/parser/ast/stmt.h>
#include <memory>

struct yy_buffer_state;

struct YYLTYPE {
    const char *start;
    const char *end;
};

#define YYLTYPE_IS_DECLARED 1  // userdefined YYLTYPE

#define YYLLOC_DEFAULT(Current, Rhs, N)                                   \
  do {                                                                    \
    if (N) {                                                              \
      (Current).start = YYRHSLOC(Rhs, 1).start;                       \
      (Current).end = YYRHSLOC(Rhs, N).end;                           \
    } else {                                                              \
      (Current).start = (Current).end = YYRHSLOC(Rhs, 0).end;             \
    }                                                                     \
  } while (0)

namespace cantor::parser {
    enum ParseError {
        SUCCESS = 0,
        SYNTAX_ERROR = 1,
    };

    constexpr const char *parse_error_to_string(ParseError e) {
        switch (e) {
            case SUCCESS:
                return "SUCCESS";
            case SYNTAX_ERROR:
                return "SYNTAX_ERROR";
            default:
                return "SYNTAX_ERROR";
        }
    }

    enum class Charset {
        CHARSET_UTF8 = 0,
        CHARSET_GBK = 1
    };

    struct SqlParserImpl;

    struct SqlParser {
        ~SqlParser();

        Charset charset{Charset::CHARSET_UTF8};
        std::string collation;
        std::vector<StmtNode *> result;
        ParseError error = SUCCESS;
        std::string syntax_err_str;
        turbo::Arena arena;
        bool is_gbk = false;
        bool has_5c = false;
        int place_holder_id = 0;
        int64_t parse_cost_nano{0};

        LocationInfo get_location(YYLTYPE loc) const {
            return {static_cast<int>(loc.start - _buffer_input), static_cast<int>(loc.end - loc.start)};
        }

        LocationInfo get_location(YYLTYPE start, YYLTYPE end) const {
            return {static_cast<int>(start.start - _buffer_input), static_cast<int>(end.end - start.start)};
        }

        std::string get_token(int location, int len) {
            return std::string(_buffer_input + location, len);
        }

        void parse(const std::string &sql);

        void change_5c_to_7f(std::string &sql);

    private:
        SqlParserImpl *impl_{nullptr};
        const char *_buffer_input{nullptr};
    };

    inline void print_stmt(Node *node, int ii = 0) {
        std::cout << "i:" << ii << " type:" << node->node_type << " ";
        node->print();
        if (node->node_type == pb::ast::NODE_TYPE_EXPR) {
            std::cout << "to_string:" << node << std::endl;
        }
    }
} // namespace cantor::parser
